package org.budo.vms.service.huawei;

import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.budo.support.fastjson.Fastjson;
import org.budo.support.http.client.Request;
import org.budo.support.http.client.Response;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.UuidUtil;
import org.budo.time.Time;
import org.budo.vms.service.api.PlayInfo;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class HuaweiVmsServiceImpl extends AbstractHuaweiVmsService {
    /**
     * singleCallByTts
     * 
     * @param displayNumber
     * @param calleeNumber
     * @param templateId
     * @param templateParas
     */
    public String callNotify(String displayNumber, String calleeNumber, PlayInfo playInfo) {
        if (null == displayNumber || null == calleeNumber || null == playInfo) {
            throw new IllegalArgumentException("#46 displayNumber=" + displayNumber + ", calleeNumber=" + calleeNumber + ", playInfo=" + playInfo);
        }

        // 语音通知API有v1.0和v2.0两个版本,请提前和管理员确认使用API的版本,并修改以下的值.
        // 注意：v要求小写

        // 构造URL,
        String url = this.getAppUrl() + "/rest/httpsessions/callnotify/" + this.getApiVersion();

        // 请求Headers
        Map<String, Object> headerMap = new HashMap<String, Object>();
        headerMap.put("Authorization", "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"");
        headerMap.put("X-WSSE", buildWsseHeader(this.getAppKey(), this.getAppSecret()));

        headerMap.put("Content-Type", "application/json");

        // 构造消息体
        Map<String, Object> map = new HashMap<>();
        map.put("displayNbr", displayNumber); // 主叫用户手机终端的来电显示号码。
        map.put("calleeNbr", calleeNumber); // 发起呼叫时所拨打的被叫号码。

        if (null != this.getStatusUrl()) {
            map.put("statusUrl", Base64.getEncoder().encodeToString(this.getStatusUrl().getBytes()));
        }

        if (null != this.getFeeUrl()) {
            map.put("feeUrl", Base64.getEncoder().encodeToString(this.getFeeUrl().getBytes()));
        }

        map.put("returnIdlePort", "true");

        // PlayInfo
        if (playInfo instanceof HuaweiTemplatePlayInfo) {
            Map<String, Object> stringObjectMap = MapUtil.stringObjectMap("templateId", ((HuaweiTemplatePlayInfo) playInfo).getTemplateId(), //
                    "templateParas", ((HuaweiTemplatePlayInfo) playInfo).getTemplateParas());
            List<Map<String, Object>> list = Arrays.asList(stringObjectMap);

            map.put("playInfoList", list); // 播放信息列表，最大支持5个，每个播放信息携带的参数都可以不相同。
        } else { // HuaweiVoicePlayInfo
            Map<String, Object> stringObjectMap = MapUtil.stringObjectMap("notifyVoice", ((HuaweiVoicePlayInfo) playInfo).getNotifyVoice());
            List<Map<String, Object>> list = Arrays.asList(stringObjectMap);

            map.put("playInfoList", list); // 播放信息列表，最大支持5个，每个播放信息携带的参数都可以不相同。
        }

        String jsonRequest = Fastjson.toJSONString(map);

        Request request = new Request();
        request.setUrl(url);
        request.setHeaders(headerMap);
        request.setRequestBody(jsonRequest);

        Response response = request.execute();

        log.info("#75 response=" + response);
        return response.bodyOrToString();
    }

    private String buildWsseHeader(String appKey, String appSecret) {
        String time = Time.now().toString("yyyy-MM-dd'T'HH:mm:ss'Z'");
        String nonce = UuidUtil.randomUuid();

        byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret);
        String hexDigest = Hex.encodeHexString(passwordDigest);

        String passwordDigestBase64Str = Base64.getEncoder().encodeToString(hexDigest.getBytes()); // JDK version≥1.8

        String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";

        return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
    }
}